package org.wattdepot.cli.command;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.util.tstamp.Tstamp;

/**
 * Implements the list total command for the command line interface.
 * 
 * @author George Lee
 *
 */
public class TotalCommand extends WattDepotCliCommand {

  /**
   * Create a new instance of the ListTotalCommand.
   * @param client The instance of the client to handle our commands.
   */
  public TotalCommand(WattDepotClient client) {
    super(client);
  }

  /**
   * Validates and performs the command.
   * @param command The command to process.
   * @return The result of the command.
   * 
   * @see org.wattdepot.cli.command.WattDepotCliCommand#doCommand(String)
   */
  @Override
  public String doCommand(String command) {
    boolean isCarbon = false;
    String source;
    XMLGregorianCalendar startDay;
    int interval;

    StringTokenizer tokenizer = new StringTokenizer(command);
    List<String> tokens = new ArrayList<String>();
    while (tokenizer.hasMoreTokens()) {
      tokens.add(tokenizer.nextToken());
    }

    if (tokens.size() != 8) {
      return this.reportError(PARAMETER_COUNT_ERROR);
    }

    if (!"generated".equals(tokens.get(2))) {
      return this.reportError(PARAMETER_ERROR + tokens.get(2));
    }
    
    if (!"day".equals(tokens.get(4))) {
      return this.reportError(PARAMETER_ERROR + tokens.get(4));
    }
    
    if (!"sampling-interval".equals(tokens.get(6))) {
      return this.reportError(PARAMETER_ERROR + tokens.get(6));
    }
    
    if ("carbon".equals(tokens.get(1))) {
      isCarbon = true;
    }
    else if (!"energy".equals(tokens.get(1))) {
      return this.reportError("Invalid type " + tokens.get(1));
    }

    source = tokens.get(3);

    try {
      startDay = Tstamp.makeTimestamp(tokens.get(5));
    }
    catch (Exception e) {
      return this.reportError(TSTAMP_ERROR + tokens.get(5));
    }

    try {
      interval = Integer.valueOf(tokens.get(7));
      if (interval <= 0) {
        return this.reportError(RANGE_ERROR + tokens.get(7));
      }
    }
    catch (NumberFormatException e) {
      return INTERVAL_ERROR + tokens.get(7);
    }

    return this.listTotal(isCarbon, source, startDay, interval);
  }
  
  /**
   * Retrieves the total carbon or energy emitted/generated by the source on the given day.
   * 
   * @param getCarbon Set to true to get the carbon emitted. Set to false to get the energy
   * generated.
   * @param source The source to get the data from.
   * @param start The day to analyze.
   * @param interval The sampling interval of the source.
   * 
   * @return The total carbon or energy emitted/generated or an error message.
   */
  private String listTotal(boolean getCarbon, String source, XMLGregorianCalendar start,
      int interval) {

    String result;
    XMLGregorianCalendar end = Tstamp.incrementDays(start, 1);

    try {
      Double returnValue;
      if (getCarbon) {
        returnValue = client.getCarbonEmitted(source, start, end, interval);
      }
      else {
        returnValue = client.getEnergyGenerated(source, start, end, interval);
      }

      result = returnValue.toString();
    }

    catch (NotAuthorizedException e) {
      result = this.reportError(CONNECTION_ERROR);
    }
    catch (ResourceNotFoundException e) {
      result = this.reportError(SOURCE_ERROR + source);
    }
    catch (BadXmlException e) {
      result = this.reportError(BAD_XML_ERROR);
    }
    catch (MiscClientException e) {
      result = this.reportError(CONNECTION_ERROR);
    }

    return result;
  }

  /**
   * Gets the help string associated with the total command.
   * 
   * @see org.wattdepot.cli.command.WattDepotCliCommand#getHelp()
   * @return Information on how to invoke the list total command.
   */
  @Override
  public String getHelp() {
    return "total [carbon|energy] generated {source} " 
      + "day {day} sampling-interval {minutes}\n"
      + "  Returns the total amount of carbon (or energy) emitted by this source "
      + "for the given day.\n";
  }
}
